/**
 * FireFly (2011)
 */
package com.firefly.logging;

import java.util.Map;
import java.util.WeakHashMap;

import com.firefly.logging.simple.SimpleLoggerPlugin;
import com.firefly.logging.simple.SimpleLoggerPluginInstance;

/**
 * 日志记录
 * 
 * @version 1.0 2011-1-1
 * @author lexloo(lexloo@gmail.com)
 * @since FireFly 1.0
 */
public class Logger {
	/**
	 * Logger级别
	 * 
	 * @version 1.0 2011-1-1
	 * @author lexloo(lexloo@gmail.com)
	 * @since FireFly 1.0
	 */
	public enum Level {
		FATAL, ERROR, WARN, INFO, DEBUG, TRACE,
	}

	private static final String FQCN = Logger.class.getName();
	/** 通过系统属性查找日志插件 */
	private static String PLUGIN_CLASS_PROP = "com.firefly.logging.Logger.pluginClass";
	/** 默认日志插件使用log4j */
	private static final String LOG4J_PLUGIN_CLASS_NAME = "com.firefly.logging.log4j.Log4jLoggerPlugin";
	/** 使用的插件类名 */
	private static String pluginClassName = null;
	/** 日志插件类 */
	private static Class<?> pluginClass = null;
	/** 日志缓存 */
	private static Map<String, Logger> cachedLoggers = new WeakHashMap<String, Logger>();

	static {
		init();
	}

	/** 日志名称 */
	private final String name;
	/** 代理插件 */
	private ILoggerPluginInstance loggerDelegate = null;

	/**
	 * 
	 * @return Logger 插件类名
	 */
	public static String getPluginClassName() {
		return Logger.pluginClassName;
	}

	/**
	 * 设置Logger插件类名
	 * 
	 * @param pluginClassName
	 *            插件类名
	 */
	public static void setPluginClassName(String pluginClassName) {
		if (!pluginClassName.equals(Logger.pluginClassName)) {
			Logger.pluginClassName = pluginClassName;
			init();
		}
	}

	/**
	 * 构造函数
	 * 
	 * @param name
	 *            Logger对象名
	 * @param loggerDelegate
	 *            代理实例
	 */
	public Logger(final String name, final ILoggerPluginInstance loggerDelegate) {
		this.name = name;
		this.loggerDelegate = loggerDelegate;
	}

	/**
	 * 返回Logger实例名
	 * 
	 * @return Logger实例名
	 */
	public String getName() {
		return name;
	}

	/**
	 * 返回Logger插件实例
	 * 
	 * @return Logger插件实例
	 */
	public ILoggerPluginInstance getLoggerPluginInstance() {
		return loggerDelegate;
	}

	public boolean isTraceEnabled() {
		return loggerDelegate.isEnabled(Level.TRACE);
	}

	public void trace(Object message) {
		loggerDelegate.log(Level.TRACE, FQCN, message);
	}

	public void trace(Object message, Object... params) {
		loggerDelegate.log(Level.TRACE, FQCN, message, params);
	}

	public boolean isDebugEnabled() {
		return loggerDelegate.isEnabled(Level.DEBUG);
	}

	public void debug(Object message) {
		loggerDelegate.log(Level.DEBUG, FQCN, message);
	}

	public void debug(Object message, Object... params) {
		loggerDelegate.log(Level.DEBUG, FQCN, message, params);
	}

	public boolean isInfoEnabled() {
		return loggerDelegate.isEnabled(Level.INFO);
	}

	public void info(Object message) {
		loggerDelegate.log(Level.INFO, FQCN, message);
	}

	public void info(Object message, Object... params) {
		loggerDelegate.log(Level.INFO, FQCN, message, params);
	}

	public void warn(Object message) {
		loggerDelegate.log(Level.WARN, FQCN, message);
	}

	public void warn(Object message, Object... params) {
		loggerDelegate.log(Level.WARN, FQCN, message, params);
	}

	public void error(Object message) {
		loggerDelegate.log(Level.ERROR, FQCN, message);
	}

	public void error(Object message, Object... params) {
		loggerDelegate.log(Level.ERROR, FQCN, message, params);
	}

	public void fatal(Object message) {
		loggerDelegate.log(Level.FATAL, FQCN, message);
	}

	public void fatal(Object message, Object... params) {
		loggerDelegate.log(Level.FATAL, FQCN, message, params);
	}

	public void log(Level level, Object message) {
		loggerDelegate.log(level, FQCN, message);
	}

	public void log(Level level, Object message, Object... params) {
		loggerDelegate.log(level, FQCN, message, params);
	}

	public static Logger getLogger(String name) {
		Logger logger = cachedLoggers.get(name);

		if (logger == null) {
			logger = getDelegatePluginInstance(name).getLogger();
			cachedLoggers.put(name, logger);
		}

		return logger;
	}

	public static Logger getLogger(Class<?> clazz) {
		return getLogger(clazz.getName());
	}

	/**
	 * 获取日志插件
	 * 
	 * @return 日志插件
	 */
	public ILoggerPlugin getLoggerPlugin() {
		return getLoggerPluginInstance().getLoggerPlugin();
	}

	/**
	 * 获取Logger插件代理
	 * 
	 * @param name
	 *            Logger名
	 * @return 日志插件代理
	 */
	private static ILoggerPluginInstance getDelegatePluginInstance(String name) {
		ILoggerPlugin plugin;
		ILoggerPluginInstance instance;
		try {
			plugin = (ILoggerPlugin) pluginClass.newInstance();
		} catch (Throwable e) {
			plugin = new SimpleLoggerPlugin();
		}

		try {
			instance = plugin.getInstance(name);
		} catch (Throwable e) {
			System.err.println("初始化日志插件失败: " + plugin + ", 原因: " + e.toString());
			instance = new SimpleLoggerPluginInstance(name, new SimpleLoggerPlugin());
		}

		return instance;
	}

	/**
	 * 初始化日志插件
	 */
	private static void init() {
		try {
			if (pluginClassName == null) {
				pluginClassName = System.getProperty(PLUGIN_CLASS_PROP, LOG4J_PLUGIN_CLASS_NAME);
			}

			ClassLoader cl = Thread.currentThread().getContextClassLoader();
			pluginClass = cl.loadClass(pluginClassName);
		} catch (Throwable e) {
			pluginClass = SimpleLoggerPluginInstance.class;
		}
	}
}
